正则表达式30分钟入门教程

2018.9.24 星期一 23:20

版本:v2.31 (2009-4-11)

1 本文目标
2 如何使用本教程
3 正则表达式到底是什么东西?
字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等等。字符串是0个或更多个字符的序列。文本也就是文字,字符串。说某个字符串匹配某个正则表达式,通常是指这个字符串里有一部分(或几部分分别)能满足表达式给出的条件。

4 入门
5 测试正则表达式
6 元字符
\b,\s,\d,\w,\W, ...,^,$
7 字符转义
8 重复
*,+,?,{n},{n,},{n,m}
9 字符类
[aeiou]就匹配任何一个英文元音字母

10 分枝条件
具体方法是用|把不同的规则分隔开;要注意各个条件的顺序
匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不
会去再管其它的条件了

12 分组
(但如果想要重复多个字符又该怎么办?)你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作

描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

11 反义
\W,\S,\D,\B,[^x]匹配除了x以外的任意字符 $_PS:??[^x]
[âeiou]匹配除了aeiou这几个字母以外的任意字符

13 后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。

\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者 kitty kitty。

你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?<Word>\w+)(或者把尖括号换成’也行:(?'Word'\w+)),这样就把\w+的组名指定为Word 了。要反向引用这个分组捕获的内容,你可以使用\k,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b

使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:
分类 |代码/语法|说明
捕获
(exp): 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?’name’exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言
(?=exp)匹配exp前面的位置 零宽度正预测先行断言
(?<=exp)匹配exp后面的位置 零宽度正回顾后发断言
(?!exp)匹配后面跟的不是exp的位置 零宽度负预测先行断言
(?<!exp)匹配前面不是exp的位置 零宽度负回顾后发断言
注释
(?#comment)这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

14 零宽断言
接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言 。

\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I’m singing while you’re dancing. 时,它会匹配sing 和danc。

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})+\b
15 负向零宽断言
前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?
例如,如果我们想查找这样的单词–它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

\b((?!abc)\w)+\b 匹配不包含连续字符串abc的单词
(?<![a-z])\d{7} 匹配前面不是小写字母的七位数字
(?<=<(\w+)>).*(?=<\/\1>)匹配 不包含属性的简单HTML标签内里的内容

16 注释
要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。

17 贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。
前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?

a.*?b 匹配 最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)

18 处理选项
IgnoreCase(忽略大小写) ,
Multiline(多行模式)更改^和$ 的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.) ,
Singleline(单行模式) :更改.的含义,使它与每一个字符匹配(包括换行符\n)
IgnorePatternWhitespace(忽略空白):忽略表达式中的非转义空白并启用由#标记的注释
ExplicitCapture(显式捕获):仅捕获已被显式命名的组。

是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。

19 平衡组/递归匹配
(?’group’) 把捕获的内容命名为group,并压入堆栈(Stack)
(?’-group’) 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
(?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
(?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败

如何把 xx <aa <bbb> <bbb> aa> yy这样的字符串里,最长的配对的尖括号内的内容捕获出来?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<                         #最外层的左括号 
[^<>]* #最外层的左括号后面的不是括号的内容
(
(
(?'Open'<) #碰到了左括号,在黑板上写一个"Open"
[^<>]* #匹配左括号后面的不是括号的内容
)+
(
(?'-Open'>) #碰到了右括号,擦掉一个"Open"
[^<>]* #匹配右括号后面不是括号的内容
)+
)*
(?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";

> #最外层的右括号

平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的<div>标签:<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>.

20 还有些什么东西没提到

联系作者
最后,来点广告……
网上的资源及本文参考文献
更新纪录

2018.9.24 星期一 23:50

knowledge is no pay,reward is kindness
0%